<?php

namespace WebmanGrpc\Serialization;

use Google\Protobuf\Internal\Message;

/**
 * Protobuf消息对象池
 * 
 * 用于减少频繁创建/销毁Protobuf消息对象的开销
 */
class MessagePool
{
    /**
     * 消息池
     * @var array
     */
    protected static array $pools = [];
    
    /**
     * 池大小配置
     * @var array
     */
    protected static array $poolConfig = [
        'max_size' => 100,  // 每个类型的最大对象数
        'min_size' => 5,    // 每个类型的最小对象数
    ];
    
    /**
     * 序列化缓存
     * @var array
     */
    protected static array $serializationCache = [];
    
    /**
     * 缓存大小配置
     * @var int
     */
    protected static int $maxCacheSize = 1000;
    
    /**
     * 设置池配置
     * 
     * @param array $config 配置数组
     * @return void
     */
    public static function setPoolConfig(array $config): void
    {
        self::$poolConfig = array_merge(self::$poolConfig, $config);
    }
    
    /**
     * 设置缓存大小
     * 
     * @param int $size 缓存大小
     * @return void
     */
    public static function setCacheSize(int $size): void
    {
        self::$maxCacheSize = $size;
    }
    
    /**
     * 从对象池获取消息对象
     * 
     * @param string $className 消息类名
     * @return Message|null 消息对象
     */
    public static function getMessage(string $className): ?Message
    {
        if (!isset(self::$pools[$className]) || empty(self::$pools[$className])) {
            return null;
        }
        
        // 从池中取出一个对象
        $message = array_pop(self::$pools[$className]);
        
        // 重置对象状态
        if (method_exists($message, 'clear')) {
            $message->clear();
        }
        
        return $message;
    }
    
    /**
     * 将消息对象归还到对象池
     * 
     * @param Message $message 消息对象
     * @return void
     */
    public static function returnMessage(Message $message): void
    {
        $className = get_class($message);
        
        // 初始化池
        if (!isset(self::$pools[$className])) {
            self::$pools[$className] = [];
        }
        
        // 检查池大小
        if (count(self::$pools[$className]) >= self::$poolConfig['max_size']) {
            return;  // 池已满，丢弃对象
        }
        
        // 归还对象到池
        self::$pools[$className][] = $message;
    }
    
    /**
     * 预热对象池
     * 
     * @param array $classNames 消息类名数组
     * @return void
     */
    public static function warmUp(array $classNames): void
    {
        foreach ($classNames as $className) {
            if (!class_exists($className)) {
                continue;
            }
            
            // 初始化池
            if (!isset(self::$pools[$className])) {
                self::$pools[$className] = [];
            }
            
            // 填充池到最小大小
            $currentSize = count(self::$pools[$className]);
            $toAdd = max(0, self::$poolConfig['min_size'] - $currentSize);
            
            for ($i = 0; $i < $toAdd; $i++) {
                try {
                    $message = new $className();
                    self::$pools[$className][] = $message;
                } catch (\Exception $e) {
                    // 忽略创建失败的对象
                }
            }
        }
    }
    
    /**
     * 获取序列化缓存
     * 
     * @param Message $message 消息对象
     * @return string|null 序列化结果
     */
    public static function getSerializationCache(Message $message): ?string
    {
        $key = self::getCacheKey($message);
        return self::$serializationCache[$key] ?? null;
    }
    
    /**
     * 设置序列化缓存
     * 
     * @param Message $message 消息对象
     * @param string $data 序列化数据
     * @return void
     */
    public static function setSerializationCache(Message $message, string $data): void
    {
        // 检查缓存大小
        if (count(self::$serializationCache) >= self::$maxCacheSize) {
            // 简单的LRU策略：移除第一个元素
            array_shift(self::$serializationCache);
        }
        
        $key = self::getCacheKey($message);
        self::$serializationCache[$key] = $data;
    }
    
    /**
     * 清空序列化缓存
     * 
     * @return void
     */
    public static function clearSerializationCache(): void
    {
        self::$serializationCache = [];
    }
    
    /**
     * 获取缓存键
     * 
     * @param Message $message 消息对象
     * @return string 缓存键
     */
    protected static function getCacheKey(Message $message): string
    {
        // 使用类名和序列化结果的哈希作为键
        $className = get_class($message);
        $hash = md5(serialize($message));
        return $className . ':' . $hash;
    }
    
    /**
     * 获取池统计信息
     * 
     * @return array 统计信息
     */
    public static function getStats(): array
    {
        $stats = [
            'pools' => [],
            'total_objects' => 0,
            'cache_size' => count(self::$serializationCache),
        ];
        
        foreach (self::$pools as $className => $pool) {
            $stats['pools'][$className] = count($pool);
            $stats['total_objects'] += count($pool);
        }
        
        return $stats;
    }
    
    /**
     * 清空所有池
     * 
     * @return void
     */
    public static function clearAll(): void
    {
        self::$pools = [];
        self::$serializationCache = [];
    }
}